﻿using System;
using System.Collections.Generic;
using System.IO.Compression;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using GzipManagerPro.IO.Helpers;

namespace GzipManagerPro.IO
{
    partial class File
    {
        public override bool ExtractTo(string path, Archive archive)
        {
            return ExtractTo(path, archive, null);
        }
        public override bool ExtractTo(string path, Archive archive, string password)
        {
            if (archive == null || !System.IO.File.Exists(archive.FileName))
                throw new System.IO.FileNotFoundException();

            archive.CheckPassword(password);

            ArchiveMessageEventArgs e = new ArchiveMessageEventArgs(1, 0, "{0}", this.Name);
            e.Level = ArchiveMessageType.FileLevel;
            e.TotalProgress = this.Length;
            e.Message = string.Format("Reading file '{0}'...", this.Name);
            int readBytes;
            // Step 1: Opening the archive file
            System.IO.FileStream stream;
            stream = new System.IO.FileStream(archive.FileName,
                System.IO.FileMode.Open,
                System.IO.FileAccess.Read,
                System.IO.FileShare.Read);


            // Step 2: Moving to the file location
            stream.Position = this.Offset;

            // Step 3: Reading file contents
            byte[] buffer = new byte[8192];
            string tempFileName = System.IO.Path.GetTempFileName();

            System.IO.FileStream tempStream = new System.IO.FileStream(tempFileName,
                System.IO.FileMode.OpenOrCreate,
                System.IO.FileAccess.ReadWrite,
                System.IO.FileShare.None);

            long totalBytes = 0;
            while (true)
            {
                readBytes = stream.Read(buffer, 0, buffer.Length);

                if (readBytes <= 0)
                    break;

                

                if (totalBytes + readBytes > this.Length)
                    readBytes = (int)(this.Length - totalBytes);

                tempStream.Write(buffer, 0, readBytes);
                e.CurrentProgress += readBytes;
                archive.OnArchiveMessage(e);
                tempStream.Flush();
                totalBytes += readBytes;

                if (totalBytes >= this.Length)
                    break;
            }

            stream.Close();
            
            path = System.IO.Path.Combine(path, this.Name);

            System.IO.FileStream writerToStream;
            writerToStream = new System.IO.FileStream(path,
                System.IO.File.Exists(path) ? System.IO.FileMode.Truncate : System.IO.FileMode.CreateNew,
                System.IO.FileAccess.Write,
                System.IO.FileShare.None);

            
            GZipStream decompressor = new GZipStream(tempStream, CompressionMode.Decompress);

            int blockSize = 8192;
            byte[] contents = new byte[blockSize];

            buffer = new byte[4];
            tempStream.Position = tempStream.Length - 4;
            tempStream.Read(buffer, 0, buffer.Length);
            e.TotalProgress = buffer.GetOriginalLength();

            tempStream.Position = 0;
            e.CurrentProgress = 0;
            e.Message = string.Format("Extracing file '{0}'...", this.Name);

            while (true)
            {    
                readBytes = decompressor.Read(contents, 0, contents.Length);

                if (readBytes <= 0)
                    break;

                writerToStream.Write(contents, 0, readBytes);

                e.CurrentProgress += readBytes;
                archive.OnArchiveMessage(e);
            }

            decompressor.Close();
            writerToStream.Close();

            return false;
        }
    }
}
